/******************************************************************************/
/*!
\file		  SoundLoader.cpp
\author 	Yip Yan Kit Anton
\par    	email: y.yip\@digipen.edu
\date   	Febuary 02, 2013
\brief

Based off FMOD

Copyright (C) 2013 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the
prior written consent of DigiPen Institute of Technology is prohibited.
 */
/******************************************************************************/
#include <string>
#include "SoundLoader.h"
#include <map>


namespace SoundWrapper
{
	static FMOD::System *system;
	static FMOD_RESULT result;
	static unsigned int version;
	static int numdrivers;
	static FMOD_SPEAKERMODE speakermode;
	static FMOD_CAPS caps;
	static std::string pathDir = "./resources/Sounds/"; // where the folder to store files are
	static FMOD::Sound *bgmSound;
	static FMOD::Channel *channel;

	static FMOD::SoundGroup	*bgmSoundGroup;
	static FMOD::SoundGroup	*sfxSoundGroup;
	static FMOD::ChannelGroup	*bgmChannelGroup;
	static FMOD::ChannelGroup	*sfxChannelGroup;

	static std::map<int,FMOD::Sound*> sfxSounds;

	static float bgmVolume;
	static float sfxVolume;
	static char name[256];

/******************************************************************************/
/*!
\brief
Exit if any errors
\param result
the variable to check
*/
/******************************************************************************/
	void ERRCHECK(FMOD_RESULT result)
	{
		if (result !=  FMOD_OK)
		{
			exit(0);
		}
	}
/******************************************************************************/
/*!
\brief
Starts the sound system
\return
true if successful
*/
/******************************************************************************/
	bool StartSoundSystem()
	{

		result = FMOD::System_Create(&system);
		ERRCHECK(result);
		result = system->getVersion(&version);
		ERRCHECK(result);
		if (version < FMOD_VERSION)
		{
			printf("Error! You are using an old version of FMOD %08x. This program requires %08x\n",
			version, FMOD_VERSION);
			return 0;
		}
		result = system->getNumDrivers(&numdrivers);
		ERRCHECK(result);
		if (numdrivers == 0)
		{
			result = system->setOutput(FMOD_OUTPUTTYPE_NOSOUND);
			ERRCHECK(result);
		}
		else
		{
			result = system->getDriverCaps(0, &caps, 0, &speakermode);
			ERRCHECK(result);
			/*
			Set the user selected speaker mode.
			*/
			result = system->setSpeakerMode(speakermode);
			ERRCHECK(result);
			if (caps & FMOD_CAPS_HARDWARE_EMULATED)
			{
				/*
				The user has the 'Acceleration' slider set to off! This is really bad
				for latency! You might want to warn the user about this.
				*/
				result = system->setDSPBufferSize(1024, 10);
				ERRCHECK(result);
			}
			result = system->getDriverInfo(0, name, 256, 0);
			ERRCHECK(result);
			if (strstr(name, "SigmaTel"))
			{
				/*
				Sigmatel sound devices crackle for some reason if the format is PCM 16bit.
				PCM floating point output seems to solve it.
				*/
				result = system->setSoftwareFormat(48000, FMOD_SOUND_FORMAT_PCMFLOAT, 0,0,
				FMOD_DSP_RESAMPLER_LINEAR);
				ERRCHECK(result);
			}
		}
		result = system->init(256, FMOD_INIT_NORMAL, 0);
		if (result == FMOD_ERR_OUTPUT_CREATEBUFFER)
		{
		/*
			Ok, the speaker mode selected isn't supported by this soundcard. Switch it
			back to stereo...
			*/
			result = system->setSpeakerMode(FMOD_SPEAKERMODE_STEREO);
			ERRCHECK(result);
			/*
			... and re-init.
			*/
			result = system->init(256, FMOD_INIT_NORMAL, 0);
		}
		ERRCHECK(result);
		// Pre tests done

		system->createSoundGroup("BGMSoundGroup",&bgmSoundGroup);
		system->createSoundGroup("SFXSoundGroup",&sfxSoundGroup);
		system->createChannelGroup("BGMChannelGroup",&bgmChannelGroup);
		system->createChannelGroup("SFXChannelGroup",&sfxChannelGroup);


		return true;
	}
	// sound init finished.
/******************************************************************************/
/*!
\brief
Loads the BGM in
\param soundBGM
filename of the bgm
\return
true if successful
*/
/******************************************************************************/
	bool LoadBGM(const char* soundBGM)
	{
		std::string concatFilename;
		concatFilename.append(pathDir);
		concatFilename.append(soundBGM);

		result = system->createStream(concatFilename.c_str(),FMOD_LOOP_NORMAL ,0,&bgmSound);
		bgmSound->setSoundGroup(bgmSoundGroup);
		ERRCHECK(result);
		return true;
	}
/******************************************************************************/
/*!
\brief
Plays the current BGM
\return
true if successful
*/
/******************************************************************************/
	bool PlayBGM()
	{
		// playing the sounds
		result = system->playSound(FMOD_CHANNEL_FREE,bgmSound,false,&channel);
		channel->setChannelGroup(bgmChannelGroup);
		// sound test end.
		return true;
	}
/******************************************************************************/
/*!
\brief
stops the BGM
\return
true if successful
*/
/******************************************************************************/
	bool stopBGM()
	{
		result = bgmChannelGroup->stop();
		ERRCHECK(result);
		return true;
	}
/******************************************************************************/
/*!
\brief
Loads the sfx into a map
\param name
enum of the value
\param soundSFX
filepath / filename
\return
true if successful
*/
/******************************************************************************/
	bool LoadSFX(int name,const char* soundSFX)
	{
		// prevent reloading
		if (sfxSounds.find(name) != sfxSounds.end())
			return false;

		std::string concatFilename;
		concatFilename.append(pathDir);
		concatFilename.append(soundSFX);
		FMOD::Sound* sfxSound;
		// system->createStream(concatFilename.c_str(),FMOD_INIT_NORMAL,0,&sfxSound);
		// Stream lags.
		result = system->createStream(concatFilename.c_str(),FMOD_NONBLOCKING,0,&sfxSound);
		sfxSound->setSoundGroup(sfxSoundGroup);
		ERRCHECK(result);

		sfxSounds.insert(std::pair<int,FMOD::Sound*>(name,sfxSound));
		return true;
	}
/******************************************************************************/
/*!
\brief
plays a sfx
\param name
key value of a map
\return
true if successful
*/
/******************************************************************************/
	bool PlaySFX(int name)
 	{
    // prevent error on play
		if (sfxSounds.find(name) != sfxSounds.end())
			return false;
      
		// playing the sounds
		result = system->playSound(FMOD_CHANNEL_FREE,sfxSounds.find(name)->second,false,&channel);
		channel->setChannelGroup(sfxChannelGroup);
		// sound test end.
		return true;
	}
/******************************************************************************/
/*!
\brief
stops all sfx sounds
\return
true if successful
*/
/******************************************************************************/
	bool stopSFXSounds()
	{
		sfxChannelGroup->stop();
		return true;
	}
/******************************************************************************/
/*!
\brief
Unloads the sound system
\return
true if successful
*/
/******************************************************************************/
	bool QuitSoundSystem()
	{
		
		for (unsigned i = 0; i < sfxSounds.size(); i++)
		{
			sfxSounds[i]->release();
		}
		sfxSounds.clear();
        result = system->release();
		ERRCHECK(result);
		return true;
	}

	bool Update()
	{
		system->update();

		return true;
	}
/******************************************************************************/
/*!
\brief
sets the bgm volume
\param bgmVol
float value of 0.0f-1.0f
*/
/******************************************************************************/
	void setBGMvolume(float bgmVol)
	{
		if (bgmVol <= 1.0f || bgmVol >= 0.0f)
		{
			bgmChannelGroup->setVolume(bgmVol);
			return;
		}
	}

/******************************************************************************/
/*!
\brief
gets the bgm volume
\return
float value of the bgm volume
*/
/******************************************************************************/
	float getBGMvolume()
	{
		float tmpInt;
		bgmChannelGroup->getVolume(&tmpInt);
		return tmpInt;
	}

/******************************************************************************/
/*!
\brief
sets the sfx volume
\param sfxVol
float value from 0.0f to 1.0f
\return
true if successful
*/
/******************************************************************************/
	void setSFXvolume(float sfxVol)
	{
		if (sfxVol <= 1.0f || sfxVol >= 0.0f)
		{
			sfxChannelGroup->setVolume(sfxVol);
			return;
		}
		sfxVolume = sfxVol;
	}
/******************************************************************************/
/*!
\brief
gets the current SFX volume
\return
0.0f to 1.0f float value
*/
/******************************************************************************/
	float getSFXvolume()
	{
		float tmpInt;
		sfxChannelGroup->getVolume(&tmpInt);
		return tmpInt;
	}
}